package com.zrc.japktool.apk.merge.manifest;

import com.google.gson.Gson;
import com.zrc.japktool.apk.merge.AssetsConfig;
import com.zrc.japktool.util.AxmlUtil;
import com.zrc.japktool.util.Base64Util;
import com.zrc.japktool.util.HexUtils;
import com.zrc.japktool.util.Zip4jUtil;
import pxb.android.Res_value;
import pxb.android.axml.Axml;
import pxb.android.axml.Util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import pxb.android.axml.R;

public class ManifestXmlEditor {
    public Axml axml;
    public Axml.Node manifest;
    public Axml.Node application;
    public String pkg;

    public ManifestXmlEditor(String apkPath) throws IOException {
        byte[] aAndroidManifest = Zip4jUtil.readFileBytes(apkPath, "AndroidManifest.xml");
        Axml axml = Axml.parse(aAndroidManifest);
        this.axml = axml;
        Axml.Node manifest = axml.findFirst("manifest");
        if (manifest == null) {
            throw new IOException("manifest 节点不存在...");
        }
        this.manifest = manifest;
        for (Axml.Node.Attr attr : manifest.attrs) {
            if (attr.name.equals("package")) {
                pkg = attr.raw;
            }
        }
        Axml.Node application = manifest.findFirst("application");
        if (application == null) {
            throw new IOException("application 节点不存在...");
        }
        this.application = application;
    }

    public ManifestXmlEditor(byte[] arscData) throws IOException {
        Axml aManifest = Axml.parse(arscData);
        this.axml = aManifest;
        Axml.Node manifest = axml.findFirst("manifest");
        if (manifest == null) {
            throw new IOException("manifest 节点不存在...");
        }
        this.manifest = manifest;
        for (Axml.Node.Attr attr : manifest.attrs) {
            if (attr.name.equals("package")) {
                pkg = attr.raw;
            }
        }
        Axml.Node application = manifest.findFirst("application");
        if (application == null) {
            throw new IOException("application 节点不存在...");
        }
        this.application = application;
    }

    public void save2ApkFile(String outApkPath) throws IOException {
        if (!outApkPath.endsWith(".apk")) {
            throw new IOException(outApkPath + " 路径错误，必须以.apk结尾...");
        }
        byte[] data = axml.toByteArray();
        Zip4jUtil.writeFileBytes(outApkPath, "AndroidManifest.xml", data,true);
    }

    public void save2ManifestXmlFile(String xmlFilePath) throws IOException {
        if (!xmlFilePath.endsWith(".xml")) {
            throw new IOException(xmlFilePath + " 路径错误，必须以.xml结尾...");
        }
        byte[] data = axml.toByteArray();
        Util.writeFile(data, new File(xmlFilePath));
    }

    public void addMetaData2ApplicationNode(String metaName, String metaValue) {
        if (application == null) {
            return;
        }
        String androidNs = "http://schemas.android.com/apk/res/android";
        boolean metaDataFound = false;

        for (Axml.Node childNode : application.children) {
            if ("meta-data".equals(childNode.name)) {
                String currentMetaName = AxmlUtil.getAndroidAttrValue(childNode, "name");
                if (AxmlUtil.equals(currentMetaName, metaName)) {
                    for (Axml.Node.Attr attr : childNode.attrs) {
                        if (androidNs.equals(attr.ns) && "value".equals(attr.name)) {
                            attr.raw = metaValue;
                            attr.value = Res_value.newStringValue(metaValue);
                            break;
                        }
                    }
                    metaDataFound = true;
                    break;
                }
            }
        }

        if (!metaDataFound) {
            Axml.Node newMetaDataNode = new Axml.Node();
            newMetaDataNode.ns = null;
            newMetaDataNode.name = "meta-data";

            Axml.Node.Attr nameAttr = new Axml.Node.Attr();
            nameAttr.ns = androidNs;
            nameAttr.name = "name";
            nameAttr.raw = metaName;
            nameAttr.value = Res_value.newStringValue(metaName);
            nameAttr.resourceId = R.attr.name;
            newMetaDataNode.attrs.add(nameAttr);

            Axml.Node.Attr valueAttr = new Axml.Node.Attr();
            valueAttr.ns = androidNs;
            valueAttr.name = "value";
            valueAttr.raw = metaValue;
            valueAttr.value = Res_value.newStringValue(metaValue);
            valueAttr.resourceId = R.attr.value;
            newMetaDataNode.attrs.add(valueAttr);

            newMetaDataNode.ln = 0;

            application.children.add(newMetaDataNode);
        }
    }

    public void merge(ManifestXmlEditor bManifestXmlEditor, String outApkPath, Map<String, String> idMap, AssetsConfig appConfig) throws Exception {
        manifest.replace(null, "package", -1, appConfig.getAppPackage(), Res_value.newStringValue(appConfig.getAppPackage()));
        // 删除A.apk的主入口
        // 1. 获取application节点
        Axml.Node mainAct = null;
        if (application != null) {
            // 2. 遍历所有activity节点查找主入口
            for (Axml.Node activity : new ArrayList<>(application.children)) {
                if ("activity".equals(activity.name)) {
                    // 3. 查找包含MAIN和LAUNCHER的intent-filter
                    List<Axml.Node> intentFiltersToRemove = new ArrayList<>();
                    for (Axml.Node child : activity.children) {
                        if ("intent-filter".equals(child.name)) {
                            boolean hasMainAction = false;
                            boolean hasLauncherCategory = false;

                            // 检查intent-filter下的action和category
                            for (Axml.Node filterChild : child.children) {
                                if ("action".equals(filterChild.name)) {
                                    String actionValue = AxmlUtil.getAndroidAttrValue(filterChild, "name");
                                    if ("android.intent.action.MAIN".equals(actionValue)) {
                                        hasMainAction = true;
                                    }
                                } else if ("category".equals(filterChild.name)) {
                                    String categoryValue = AxmlUtil.getAndroidAttrValue(filterChild, "name");
                                    if ("android.intent.category.LAUNCHER".equals(categoryValue)) {
                                        hasLauncherCategory = true;
                                    }
                                }
                            }

                            // 如果同时包含MAIN和LAUNCHER，则标记为要删除的intent-filter
                            if (hasMainAction && hasLauncherCategory) {
                                intentFiltersToRemove.add(child);
                            }
                        }
                    }

                    // 4. 移除标记的intent-filter节点
                    for (Axml.Node filter : intentFiltersToRemove) {
                        mainAct = activity;
                        activity.children.remove(filter);
                    }
                }
            }
        }

        if (mainAct != null) {
            for (Axml.Node.Attr attr : mainAct.attrs) {
                if (attr.name.equals("name")) {
                    appConfig.setAppAct(attr.value.raw);
                }
            }
        }

        if (appConfig.getChannel().equals("oppo")) {
            bManifestXmlEditor.addMetaData2ApplicationNode("app_id", appConfig.getAppId());
            bManifestXmlEditor.addMetaData2ApplicationNode("app_key", appConfig.getAppKey());
            bManifestXmlEditor.addMetaData2ApplicationNode("app_config", Base64Util.encrypt(new Gson().toJson(appConfig)));
        }

        if (appConfig.getChannel().equals("vivo")) {
            bManifestXmlEditor.addMetaData2ApplicationNode("vivoUnionAppId", appConfig.getAppId());
            bManifestXmlEditor.addMetaData2ApplicationNode("app_config", Base64Util.encrypt(new Gson().toJson(appConfig)));
        }

        if (appConfig.getChannel().equals("huawei")) {
            bManifestXmlEditor.addMetaData2ApplicationNode("com.huawei.hms.client.appid", appConfig.getAppId());
            bManifestXmlEditor.addMetaData2ApplicationNode("com.huawei.hms.client.cpid", appConfig.getAppId());
            bManifestXmlEditor.addMetaData2ApplicationNode("app_config", Base64Util.encrypt(new Gson().toJson(appConfig)));
        }

        if (appConfig.getChannel().equals("honor")) {
            bManifestXmlEditor.addMetaData2ApplicationNode("app_config", Base64Util.encrypt(new Gson().toJson(appConfig)));
        }

        //修改bManifest中id
        AxmlUtil.traverseAndModifyNodes(bManifestXmlEditor.axml.firsts, idMap);

        for (Axml.Node.Attr attr : manifest.attrs) {
            if (attr.name.equals("versionName")) {
                attr.value = Res_value.newStringValue(appConfig.getAppVersionName());
                attr.raw = appConfig.getAppVersionName();
            }

            if (attr.name.equals("versionCode")) {
                attr.value = Res_value.newDecInt(appConfig.getAppVersionCode());
            }
        }

        for (Axml.Node.Attr attr : application.attrs) {
            if (attr.name.equals("debuggable")) {
                attr.value = Res_value.newFalse();
                attr.raw = "false";
            }

            if (attr.name.equals("testOnly")) {
                attr.value = Res_value.newFalse();
                attr.raw = "false";
            }
        }

        // 递归合并节点
        mergeNodes(manifest, bManifestXmlEditor.manifest);

        // 将合并后的Axml转换为字节数组并写入输出APK
        byte[] mergedManifest = axml.toByteArray();
        Zip4jUtil.writeFileBytes(outApkPath, "AndroidManifest.xml", mergedManifest,true);

    }

    private void mergeNodes(Axml.Node aParent, Axml.Node bParent) {
        for (Axml.Node bChild : bParent.children) {
            Axml.Node existingChild = AxmlUtil.findExistingChild(aParent, bChild);// 检查A中是否已存在相同节点
            if (existingChild != null) {
                mergeNodes(existingChild, bChild); // 存在则递归合并子节点的子节点
            } else {
                Axml.Node copiedNode = AxmlUtil.copyNode(bChild);// 不存在则复制B的节点到A中
                aParent.children.add(copiedNode);
            }
        }
    }

    public String getAppNameId() {
        String androidNs = "http://schemas.android.com/apk/res/android";
        for (Axml.Node.Attr attr : application.attrs) {
            if (androidNs.equals(attr.ns) && "label".equals(attr.name)) {
                return HexUtils.formatHexId(attr.value.data);
            }
        }
        return null;
    }

    public String getAppNameValue() {
        String androidNs = "http://schemas.android.com/apk/res/android";
        for (Axml.Node.Attr attr : application.attrs) {
            if (androidNs.equals(attr.ns) && "name".equals(attr.name)) {
                Res_value resValue =attr.value;
                return attr.raw;
            }
        }
        return null;
    }

    public void modifiyAppNameValue(String value,boolean needAdd) {
        String androidNs = "http://schemas.android.com/apk/res/android";
        Axml.Node.Attr targetAttr = null;
        for (Axml.Node.Attr attr : application.attrs) {
            if (androidNs.equals(attr.ns) && "name".equals(attr.name)) {
                targetAttr=attr;
                break;
            }
        }
        if (targetAttr!=null) {
            targetAttr.raw = value;
            targetAttr.value.raw = value;
        }else {
            if (needAdd) {
                Axml.Node.Attr newAppNameAttr = new Axml.Node.Attr();
                newAppNameAttr.ns = androidNs;
                newAppNameAttr.name = "name";
                newAppNameAttr.raw = value;
                newAppNameAttr.value = Res_value.newStringValue(value);
                application.attrs.add(newAppNameAttr);
            }
        }
    }

    public void deleteAppComponentFactory() {
        String androidNs = "http://schemas.android.com/apk/res/android";
        Axml.Node.Attr targetAttr = null;
        for (Axml.Node.Attr attr : application.attrs) {
            if (androidNs.equals(attr.ns) && "appComponentFactory".equals(attr.name)) {
                targetAttr=attr;
                break;
            }
        }
        if (targetAttr!=null) {
            application.attrs.remove(targetAttr);
        }
    }

    /**
     * 获取Application节点的theme属性值
     * @return theme属性值（如"@style/AppTheme"），如果不存在则返回null
     */
    public Axml.Node.Attr getApplicationTheme() {
        String androidNs = "http://schemas.android.com/apk/res/android";
        for (Axml.Node.Attr attr : application.attrs) {
            if (androidNs.equals(attr.ns) && "theme".equals(attr.name)) {
                return attr;
            }
        }
        return null;
    }

    /**
     * 修改Application节点的theme属性（使用已有的Attr对象）
     * @param themeAttr 新的theme属性对象
     */
    public void modifyApplicationTheme(Axml.Node.Attr themeAttr) {
        if (themeAttr == null) {
            return;
        }
        
        String androidNs = "http://schemas.android.com/apk/res/android";
        
        // 先移除原有的theme属性
        Axml.Node.Attr oldThemeAttr = null;
        for (Axml.Node.Attr attr : application.attrs) {
            if (androidNs.equals(attr.ns) && "theme".equals(attr.name)) {
                oldThemeAttr = attr;
                break;
            }
        }
        
        if (oldThemeAttr != null) {
            application.attrs.remove(oldThemeAttr);
        }
        
        // 添加新的theme属性
        application.attrs.add(themeAttr);
    }

    public List<String> getAppLogoIds() {
        List<String> ids = new ArrayList<>();
        String androidNs = "http://schemas.android.com/apk/res/android";
        for (Axml.Node.Attr attr : application.attrs) {
            if (androidNs.equals(attr.ns) && "icon".equals(attr.name)) {
                ids.add(HexUtils.formatHexId(attr.value.data));
                continue;
            }
            if (androidNs.equals(attr.ns) && "roundIcon".equals(attr.name)) {
                ids.add(HexUtils.formatHexId(attr.value.data));
            }
        }
        return ids;
    }

    private void replaceAllNodeAttr(Axml.Node node, String targetPkg) {
        String originalPkg = this.pkg != null ? this.pkg.trim() : "";
        String normalizedTarget = targetPkg != null ? targetPkg.trim() : "";
        if (node == null || normalizedTarget.isEmpty() || originalPkg.equals(normalizedTarget)) {
            return;
        }
        if (node.attrs != null && !node.attrs.isEmpty()) {
            for (Axml.Node.Attr attr : node.attrs) {
                if (attr.raw != null && attr.raw.contains(originalPkg)) {
                    attr.raw = attr.raw.replace(originalPkg, normalizedTarget);
                }
                if (attr.value instanceof Res_value) {
                    Res_value resValue = (Res_value) attr.value;
                    if (resValue.raw != null && resValue.raw.contains(originalPkg)) {
                        resValue.raw = resValue.raw.replace(originalPkg, normalizedTarget);
                    }
                }
            }
        }
        if (node.children != null && !node.children.isEmpty()) {
            for (Axml.Node childNode : node.children) {
                replaceAllNodeAttr(childNode, normalizedTarget);
            }
        }
    }

    public void replaceAllNodeAttr(String targetPkg) {
        if (this.axml == null || this.axml.firsts == null) {
            return;
        }
        for (Axml.Node rootNode : this.axml.firsts) {
            replaceAllNodeAttr(rootNode, targetPkg);
        }
        replaceAllNodeAttr(this.manifest, targetPkg);
    }

//    public void modifyScreenOrientation(boolean appScreenmode) {
//        String androidNs = "http://schemas.android.com/apk/res/android";
//        String screenOrientationAttr = "screenOrientation";
//        String targetSplash = "com.jxsdk.api.activity.SplashActivity";
//        String targetWelcome = "com.jxsdk.api.activity.WelcomeActivity";
//
//        int orientationValue = appScreenmode ? 1 : 0; // 1:横屏, 0:竖屏(通常值为ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE和PORTRAIT)
//        // 过滤activity
//        List<Axml.Node> activityNodes = new ArrayList<>();
//        for (Axml.Node child : application.children) {
//            if ("activity".equals(child.name)) {
//                for (Axml.Node.Attr attr : child.attrs) {
//                    // 检查属性是否属于android命名空间且名称为"name"
//                    if (androidNs.equals(attr.ns) && "name".equals(attr.name)) {
//                        if (attr.value.type == Res_value.TYPE_STRING) {
//                            String activityName = attr.raw;
//                            if (targetSplash.equals(activityName) || targetWelcome.equals(activityName)) {
//                                activityNodes.add(child);
//                                break; // 找到匹配的Activity后退出内层循环
//                            }
//                        }
//                    }
//                }
//            }
//        }
//
//        // 修改screenOrientation属性
//        for (Axml.Node child : activityNodes) {
//            Axml.Node.Attr orientationAttr = null;
//            for (Axml.Node.Attr attr : child.attrs) {
//                // 检查是否已存在android:screenOrientation属性
//                if (androidNs.equals(attr.ns) && screenOrientationAttr.equals(attr.name)) {
//                    orientationAttr = attr;
//                    break;
//                }
//            }
//            //竖版16842782 横板
//            if (orientationAttr != null) {
//                // 更新已有属性值
//                orientationAttr.value = Res_value.newDecInt(orientationValue);
//            } else {
//                // 添加新的android:screenOrientation属性
//                Axml.Node.Attr newAttr = new Axml.Node.Attr();
//                newAttr.ns = androidNs; // 设置命名空间
//                newAttr.name = screenOrientationAttr; // 设置属性名(不带前缀)
//                newAttr.value = Res_value.newDecInt(orientationValue);
//                newAttr.resourceId=16842782;//固定的id不知道什么原因必须设置
//                child.attrs.add(newAttr);
//            }
//        }
//    }

    public void modifyScreenOrientation(boolean appScreenmode) {
        String androidNs = "http://schemas.android.com/apk/res/android";
        String screenOrientationAttr = "screenOrientation";
        String targetSplash = "com.jxsdk.api.activity.SplashActivity";
        String targetWelcome = "com.jxsdk.api.activity.WelcomeActivity";

        int orientationValue = appScreenmode ? 1 : 0;
        List<Axml.Node> activityNodes = new ArrayList<>();
        for (Axml.Node child : application.children) {
            if ("activity".equals(child.name)) {
                for (Axml.Node.Attr attr : child.attrs) {
                    if (androidNs.equals(attr.ns) && "name".equals(attr.name)) {
                        if (attr.value.type == Res_value.TYPE_STRING) {
                            String activityName = attr.raw;
                            if (targetSplash.equals(activityName) || targetWelcome.equals(activityName)) {
                                activityNodes.add(child);
                                break;
                            }
                        }
                    }
                }
            }
        }

        for (Axml.Node child : activityNodes) {
            Axml.Node.Attr orientationAttr = null;
            for (Axml.Node.Attr attr : child.attrs) {
                if (androidNs.equals(attr.ns) && screenOrientationAttr.equals(attr.name)) {
                    orientationAttr = attr;
                    break;
                }
            }
            if (orientationAttr != null) {
                orientationAttr.value = Res_value.newDecInt(orientationValue);
            } else {
                Axml.Node.Attr newAttr = new Axml.Node.Attr();
                newAttr.ns = androidNs;
                newAttr.name = screenOrientationAttr;
                newAttr.value = Res_value.newDecInt(orientationValue);
                newAttr.resourceId = R.attr.screenOrientation;
                child.attrs.add(newAttr);
            }
        }
    }

    public Axml.Node findMainActivityNode() {
        Axml.Node mainAct = null;
        if (application != null) {
            for (Axml.Node activity : new ArrayList<>(application.children)) {
                if ("activity".equals(activity.name)) {
                    for (Axml.Node child : activity.children) {
                        if ("intent-filter".equals(child.name)) {
                            boolean hasMainAction = false;
                            boolean hasLauncherCategory = false;
                            for (Axml.Node filterChild : child.children) {
                                if ("action".equals(filterChild.name)) {
                                    String actionValue = AxmlUtil.getAndroidAttrValue(filterChild, "name");
                                    if ("android.intent.action.MAIN".equals(actionValue)) {
                                        hasMainAction = true;
                                    }
                                } else if ("category".equals(filterChild.name)) {
                                    String categoryValue = AxmlUtil.getAndroidAttrValue(filterChild, "name");
                                    if ("android.intent.category.LAUNCHER".equals(categoryValue)) {
                                        hasLauncherCategory = true;
                                    }
                                }
                            }
                            if (hasMainAction && hasLauncherCategory) {
                                mainAct = activity;
                            }
                        }
                    }
                }
            }
        }
        return mainAct;
    }

    public String getMainActivity() {
        String mainAct = null;
        try {
            Axml.Node node = findMainActivityNode();
            if (node != null) {
                for (Axml.Node.Attr attr : node.attrs) {
                    if (attr.name.equals("name")) {
                        mainAct = attr.raw;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return mainAct;
    }

    public static void main(String[] args) throws IOException {
        ManifestXmlEditor manifestXmlEditor = new ManifestXmlEditor("C:\\Users\\15666\\Desktop\\test\\oppo.apk");
        manifestXmlEditor.modifyScreenOrientation(false);
    }

}
